# ----------------------------------------------------------------------------
#       Copyright (C) 2013-2014 Huynh Vi Lam  <domovilam@gmail.com>
#
#       This file is part of pimucha.
#
#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#	
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#	
#	You should have received a copy of the GNU General Public License
#	along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ----------------------------------------------------------------------------



# ----------------------------------------------------------------------------
# Script for devices and controllers
# with serial interface
# Require python-serial version >= 2.5
# Feature findports need python-serial version >= 2.6
# Python version 2.7.x and 3.x
# ----------------------------------------------------------------------------
# pySerial
# --------
# - Website: http://pyserial.sourceforge.net/
# - Documentation and source code pySerial is used as base for development
# ----------------------------------------------------------------------------


import logging,serial,sys
from ..tools.serialtools import findports

logger = logging.getLogger()


class DEVserial(object):

    def __init__(self, port=None):
        self.port = port
        self._baudrate = 4800
        self._interCharTimeout = None
        self._handle = None
        self._timeout = 1
        self.opened = False

    def open(self):
        logger.debug("Opening serial port %s...." % self.port)
        if not self.port:
            port = findports()
            if port:
                self.port = port
            else:
                self.port = 'PortUnavailable'
                return
        try:
            self._handle = serial.Serial(port=self.port,
                                         baudrate=self._baudrate,
                                         interCharTimeout=self._interCharTimeout,
                                         timeout=self._timeout)
            self._handle.flush()
            self.opened = True
        except Exception as e:
            logger.critical("%s : %s", repr(e.__class__), str(e))
            self.port = 'PortUnavailable'
            logger.warning("Please check the port for the device")

    def close(self):
        logger.debug("Closing serial device %s...." % self.port)
        if self._handle : self._handle.close()

    def excepts(self,e):
        if 'Access denied' in str(e):
            # [Errno 13] Access denied (insufficient permissions)
            logger.critical("%s : %s", repr(e.__class__), str(e))
            self.opened = False
        elif str(e) == 'device reports readiness to read but returned no data (device disconnected?)':
            logger.critical("%s : %s", repr(e.__class__), str(e))
            self.opened = False
        else:
            logger.debug("%s : %s", repr(e.__class__), str(e))

    def write(self, byteh):
        """
        Write a byte
        byteh as Hex string '0xF0'
        """
        try:
            if sys.hexversion > 0x030000F0:
                 n = self._handle.write(bytes.fromhex(byteh[2:]))
            else:
                 n = self._handle.write(chr(int(byteh,16)))
            logger.debug("Writing %s with result %s", byteh, repr(n))
            return n
        except Exception as e:
            self.excepts(e)

    def writes(self, sequenceh):
        """
        Write a byte
        sequenceh as sequence Hex string "0d00000000000000000000000000"
        """
        try:
            self._handle.timeout = 1
            if sys.hexversion > 0x030000F0:
                 n = self._handle.write(bytes.fromhex(sequenceh))
            else:
                 n = self._handle.write(sequenceh.decode('hex'))
            self._handle.timeout = 0
            logger.debug("Writing %s with result %s", sequenceh, repr(n))
            return n
        except Exception as e:
            self.excepts(e)
        
    def read(self):
        """
        Read a byte and
        return the byte as integer
        """
        try:
            res = self._handle.read()
            if res == b"":
                return None
            return ord(res)
        except Exception as e:
            self.excepts(e)
        
    def readb(self):
        """
        Read a byte and
        return this byte
        """
        try:
            res = self._handle.read()
            #if res == b"":
            #    return None
            #logger.debug("Read %s", res)
            return serial.to_bytes(res)
        except Exception as e:
            self.excepts(e)
        
    def readh(self):
        """
        Read a byte and
        return this byte as hex string
        """
        try:
            res = self._handle.read()
            if res == b"":
                return None
            return "0x%02x" % ord(res)
        except Exception as e:
            self.excepts(e)
